﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using DataTier.Entities;
using DataTier.Helpers;

namespace DataTier.Repository
{
    /// <summary>
    /// Репозиторий для работы с заказами
    /// </summary>
    public class OrdersRepository : RepositoryBase
    {
        public OrdersRepository()
        {

        }

        public OrdersRepository(IDbConnection connection)
            : base(connection)
        {

        }


        /// <summary>
        /// Возвращает список Товаров, в которых существуют неотгруженные товары
        /// </summary>
        /// <param name="currentUserId"></param>
        /// <returns></returns>
        public List<OrderEntity> GetNotShippedGoodsOrderList(int currentUserId, SearchParameters param = null, string sortExpression = null, string direction = null)
        {
            using (var dbcontext = CreateDataContext())
            {
                var orders = dbcontext.Order
                    .Include("ExpendBill")
                    .Include("ExpendBill.ExpendBillSpec")
                    //.Include("ExpendBill.ExpendBillSpec.Product")
                    .Include("OrderSpec")
                    //.Include("OrderSpec.Product")
                    .Include("State")
                    .Include("User")
                    .Where(o => o.StateId == (int)StateEnum.CreatedAccount || o.StateId == (int)StateEnum.PartialDispatch)
                    .OrderBy(o => o.Id)
                    .ToList();

                // Список Заказов, у которых нет вообще Расходных накладных
                List<Order> ordersNotExpendBill = orders.Where(o => o.ExpendBill.Count == 0).ToList();

                // Список товаров с указанием признака - отгружася ли он
                Dictionary<int, Dictionary<int, int>> shippedProducts = new Dictionary<int, Dictionary<int, int>>();

                // Список Заказов, к которым есть Расходные накладные, с существующими неотгруженными товарами
                List<Order> ordersNotShippedGoods = new List<Order>();

                // Список Заказов, у которых есть Расходные накладные
                var ordersWithExpendBill = orders.Where(o => o.ExpendBill.Count != 0).ToList();
                foreach (var order in ordersWithExpendBill)
                {
                    // Список всех товаров в спецификации Заказа в виде пар <ключ, количество>
                    var orderSpec = order.OrderSpec.ToList();
                    Dictionary<int, int> orderProducts = new Dictionary<int, int>();
                    foreach (var s in orderSpec)
                        orderProducts.Add(s.ProductId, s.Count);

                    // Список всех товаров в спецификациях Расходных накладных Заказа в виде пар <ключ, количество>
                    Dictionary<int, int> billProducts = new Dictionary<int, int>();

                    // Цикл по спецификациям всех Расходных накладных для составления списка всех товаров во всех накладных
                    foreach (var bill in order.ExpendBill)
                    {
                        var billSpec = bill.ExpendBillSpec.ToList();
                        foreach (var s in billSpec)
                        {
                            if (billProducts.ContainsKey(s.ProductId))
                                billProducts[s.ProductId] = billProducts[s.ProductId] + s.Count;
                            else
                                billProducts.Add(s.ProductId, s.Count);
                        }
                    }
                    
                    // Сравнить два ОТСОРТИРОВАННЫХ словаря (это важно т.к. неотсортированные некорректно сравниваются) и если словари неравны, то этот Заказ надо добавить в список нужных Заказов
                    if (!Enumerable.SequenceEqual(orderProducts.OrderBy(op => op.Key), billProducts.OrderBy(bp => bp.Key))) //if (!Enumerable.SequenceEqual(orderProducts, billProducts))
                        ordersNotShippedGoods.Add(order);

                    // Список отгруженных товаров для каждого Заказа
                    //shippedProducts.Add(order.Id, billProducts.Select(b => b.Key).ToList());
                    shippedProducts.Add(order.Id, billProducts);
                }

                // Объединяем два списка:
                //           - Список Заказов, у которых нет вообще Расходных накладных
                //           - Список Заказов, к которым есть Расходные накладные, с существующими неотгруженными товарами
                List<Order> returnedOrderList = ordersNotExpendBill.Concat(ordersNotShippedGoods).ToList();


                var orderList = returnedOrderList.Select(o => EntityHelper.GetOrderEntity(o)).ToList();
                foreach (var entity in orderList)
                {
                    // Список Id продуктов, которые отгружены в рамках рассматриваемого Заказа
                    List<int> prodIds = null;
                    if (shippedProducts.ContainsKey(entity.Header.Id))
                        prodIds = shippedProducts[entity.Header.Id].Select(sp => sp.Key).ToList();

                    // Цикл по товарам в спецификации Заказа. Если рассматриваемый товар есть в списке отгруженных, то выставляется признак TRUE
                    foreach (var entitySpec in entity.Specification)
                        if (prodIds != null && prodIds.Contains(entitySpec.Specification.ProductId) && shippedProducts[entity.Header.Id][entitySpec.Specification.ProductId] == entitySpec.Specification.Count)
                        {
                            entitySpec.IsShipped = true; // Если Id продукта найдено в списке Id продуктов, отгруженных и количество отгруженны равно общему количеству в Заказе
                        }
                        else if (prodIds != null && prodIds.Contains(entitySpec.Specification.ProductId) && shippedProducts[entity.Header.Id][entitySpec.Specification.ProductId] != entitySpec.Specification.Count)
                        { 
                            // Пересчет количества и суммы НЕОТГРУЖЕННЫХ товаров в Заказе
                            entitySpec.Specification.Count = entitySpec.Specification.Count - shippedProducts[entity.Header.Id][entitySpec.Specification.ProductId];
                            entitySpec.Specification.Summa = (double)entitySpec.Specification.Count * (entitySpec.Specification.Price.HasValue ? entitySpec.Specification.Price.Value : 0.0);
                        }
                }

                return orderList;
            }
        }

        
        /// <summary>
        /// Возвращает список неотгруженных товаров с их количеством
        /// </summary>
        /// <param name="currentUserId"></param>
        /// <param name="param"></param>
        /// <param name="sortExpression"></param>
        /// <param name="direction"></param>
        /// <returns></returns>
        public List<OrderSpec> GetNotShippedGoodsList(int currentUserId, SearchParameters param = null, string sortExpression = null, string direction = null)
        {
            var list = GetNotShippedGoodsOrderList(currentUserId);

            if (list == null)
                return null;

            #region Формирование списка товаров с количеством. Для этого используется в качестве контейнера объект OrderSpec
            
            var orderSpecList = new List<OrderSpec>();
            foreach (var orderEntity in list)
            {
                var spec = orderEntity.Specification.Where(s => s.IsShipped != true).Select(o => o.Specification).ToList();
                foreach (var s in spec)
                {
                    if (orderSpecList.Where(os => os.ProductId == s.ProductId).Any())
                    {
                        // Товар существует, надо только увеличить количество, сумму
                        var product = orderSpecList.Where(os => os.ProductId == s.ProductId).FirstOrDefault();
                        product.Count += s.Count;
                        product.Summa += ((double)s.Count) * (s.Price.HasValue ? s.Price.Value : 0.0);
                    }
                    else
                    {
                        // Товар не существует, надо добавить в список
                        var product = new OrderSpec()
                        {
                            Artikul = s.Artikul,
                            Count = s.Count,
                            Price = s.Price,
                            ProductId = s.ProductId,
                            IsUnavailable = s.IsUnavailable,
                            ProductName = s.ProductName,
                            Summa = s.Summa,
                            SupplierArtikul = s.SupplierArtikul,
                            SupplierName = s.SupplierName
                        };
                        orderSpecList.Add(product);
                    }
                }
            }

            #endregion Формирование списка товаров с количеством. Для этого используется в качестве контейнера объект OrderSpec

            #region Применение фильтров
            if (param != null)
            {
                if (!string.IsNullOrEmpty(param.ProductName))
                    orderSpecList = orderSpecList
                        .Where(s => s.ProductName.Length >= param.ProductName.Length && s.ProductName.Substring(0, param.ProductName.Length).ToLower() == param.ProductName.ToLower()).ToList(); // Начинается со строки

                if (!string.IsNullOrEmpty(param.ProductSupplierArtikul))
                    orderSpecList = orderSpecList
                        .Where(s => s.SupplierArtikul != null && s.SupplierArtikul.Length >= param.ProductSupplierArtikul.Length && s.SupplierArtikul.Substring(0, param.ProductSupplierArtikul.Length).ToLower() == param.ProductSupplierArtikul.ToLower()).ToList(); // Начинается со строки

                if (!string.IsNullOrEmpty(param.ProductSupplierName))
                    orderSpecList = orderSpecList
                        .Where(s => s.SupplierName != null && s.SupplierName.Length >= param.ProductSupplierName.Length && s.SupplierName.ToLower() == param.ProductSupplierName.ToLower()).ToList(); // Совпадает со строкой
            }
            #endregion Применение фильтров

            #region Применение сортировки

            if (string.IsNullOrEmpty(sortExpression))
                sortExpression = "ProductId";

            bool isAscending = false;
            if (!string.IsNullOrEmpty(direction) && direction.ToLower() == "asc")
                isAscending = true;

            if (sortExpression == "ProductId")
            {
                if (isAscending)
                    orderSpecList = orderSpecList.OrderBy(s => s.ProductId).ToList();
                else
                    orderSpecList = orderSpecList.OrderByDescending(s => s.ProductId).ToList();
            }
            else if (sortExpression == "ProductName")
            {
                if (isAscending)
                    orderSpecList = orderSpecList.OrderBy(s => s.ProductName).ToList();
                else
                    orderSpecList = orderSpecList.OrderByDescending(s => s.ProductName).ToList();
            }
            else if (sortExpression == "Count")
            {
                if (isAscending)
                    orderSpecList = orderSpecList.OrderBy(s => s.Count).ToList();
                else
                    orderSpecList = orderSpecList.OrderByDescending(s => s.Count).ToList();
            }
            else if (sortExpression == "SupplierArtikul")
            {
                if (isAscending)
                    orderSpecList = orderSpecList.OrderBy(s => s.SupplierArtikul).ToList();
                else
                    orderSpecList = orderSpecList.OrderByDescending(s => s.SupplierArtikul).ToList();
            }
            else if (sortExpression == "SupplierName")
            {
                if (isAscending)
                    orderSpecList = orderSpecList.OrderBy(s => s.SupplierName).ToList();
                else
                    orderSpecList = orderSpecList.OrderByDescending(s => s.SupplierName).ToList();
            }

            #endregion Применение сортировки

            return orderSpecList;
        }


        /// <summary>
        /// Возвращает объект Заказ
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public OrderEntity GetOrder(int currentUserId, int id)
        {
            using (var dbcontext = CreateDataContext())
            {
                var order = dbcontext.Order
                    .Include("ExpendBill")
                    .Include("ExpendBill.ExpendBillSpec")
                    //.Include("ExpendBill.ExpendBillSpec.Product")
                    .Include("OrderSpec")
                    //.Include("OrderSpec.Product")
                    .Include("State")
                    .Include("User")
                    .Include("User.CostsCenter")
                    .Include("User.CostsCenter.Department")
                    .Include("User.CostsCenter.Department.JuridicalPerson")
                    .Where(o => o.Id == id).FirstOrDefault();

                var entity = EntityHelper.GetOrderEntity(order);


                // Список товаров с указанием признака - отгружася ли он
                Dictionary<int, List<int>> shippedProducts = new Dictionary<int, List<int>>();


                // Список всех товаров в спецификации Заказа в виде пар <ключ, количество>
                var orderSpec = order.OrderSpec.ToList();
                Dictionary<int, int> orderProducts = new Dictionary<int, int>();
                foreach (var s in orderSpec)
                    orderProducts.Add(s.ProductId, s.Count);

                // Список всех товаров в спецификациях Расходных накладных Заказа в виде пар <ключ, количество>
                Dictionary<int, int> billProducts = new Dictionary<int, int>();

                Dictionary<int, int> notShippedProducts = new Dictionary<int, int>();
                if (order.ExpendBill.Any())
                {
                    // Цикл по спецификациям всех Расходных накладных для составления списка всех товаров во всех накладных
                    foreach (var bill in order.ExpendBill)
                    {
                        var billSpec = bill.ExpendBillSpec.ToList();
                        foreach (var s in billSpec)
                        {
                            if (billProducts.ContainsKey(s.ProductId))
                                billProducts[s.ProductId] = billProducts[s.ProductId] + s.Count;
                            else
                                billProducts.Add(s.ProductId, s.Count);
                        }
                    }
                    notShippedProducts = ProductDictionaryHelper.Except(orderProducts, billProducts);
                }

                // Цикл по товарам в спецификации Заказа. Если рассматриваемый товар есть в списке неотгруженных, то выставляется признак FALSE
                foreach (var entitySpec in entity.Specification)
                    if (notShippedProducts.ContainsKey(entitySpec.Specification.ProductId))
                        entitySpec.IsShipped = false;
                    else
                        entitySpec.IsShipped = true;
                

                return entity;
            }
        }


        /// <summary>
        /// Возвращает фильтрованный список Заказов
        /// </summary>
        /// <returns></returns>
        public List<OrderFullInfoEntity> GetOrderList(int currentUserId, bool onlyIts, int numPage, int onPage, SearchParameters param = null, string sortExpression = null, string direction = null)
        {
            using (var dbcontext = CreateDataContext())
            {
                IQueryable<Order> orders = GetOrderListQueryable(dbcontext, currentUserId, onlyIts, numPage, onPage, param, sortExpression, direction);
                List<Order> orderList = orders.ToList();
                return EntityHelper.GetOrderFullInfoEntityList(orderList);
            }
        }

        private IQueryable<Order> GetOrderListQueryable(DBModelContainer dbcontext, int currentUserId, bool onlyIts, int numPage, int onPage, SearchParameters param = null, string sortExpression = null, string direction = null)
        {
                //List<OrderFullInfo> list = dbcontext.GetAllOrders();
                //var list = dbcontext.GetAllOrders();
                IQueryable<Order> orders = dbcontext.Order
                    .Include("OrderSpec")
                    .Include("OrderSpec.Product")
                    .Include("State")

                    .Include("User")
                    .Include("User.CostsCenter")
                    .Include("User.CostsCenter.Department")
                    .Include("User.CostsCenter.Department.JuridicalPerson")
                    .Include("User.CostsCenter.Department.JuridicalPerson.Company");

                // Показывать Только свои документы
                if (onlyIts)
                    orders = orders.Where(o => o.CreatedUserId == ((onlyIts) ? currentUserId : o.CreatedUserId));

                #region Применение фильтров
                if (param != null)
                {
                    //orderstmp = orders.Where(o => o.User.FIO.Contains(param.CreatedUser));
                    if (!string.IsNullOrEmpty(param.OrderCreatedUser))
                        orders = orders
                            .Where(o => o.User.FIO.ToLower().Contains(param.OrderCreatedUser.ToLower())); // Вхождение строки
                    //.Where(o => o.User.FIO.Substring(0, param.OrderCreatedUser.Length).ToLower() == param.OrderCreatedUser.ToLower()); // Начинается со строки

                    if (!string.IsNullOrEmpty(param.OrderNumber))
                        orders = orders
                            .Where(o => o.Number.Substring(0, param.OrderNumber.Length).ToLower() == param.OrderNumber.ToLower()); // Начинается со строки

                    if (!string.IsNullOrEmpty(param.Department))
                        orders = orders
                            .Where(o => o.User.CostsCenter.Department.Name.ToLower().Contains(param.Department.ToLower())); // Вхождение строки
                    //.Where(o => o.User.CostsCenter.Department.Name.Substring(0, param.Department.Length).ToLower() == param.Department.ToLower()); // Начинается со строки

                    if (!string.IsNullOrEmpty(param.CostsCentr))
                        orders = orders
                            .Where(o => o.User.CostsCenter.Name.ToLower().Contains(param.CostsCentr.ToLower())); // Вхождение строки
                    //.Where(o => o.User.CostsCenter.Name.Substring(0, param.CostsCentr.Length).ToLower() == param.CostsCentr.ToLower()); // Начинается со строки

                    if (!string.IsNullOrEmpty(param.JuridicalPerson))
                        orders = orders
                            .Where(o => o.User.CostsCenter.Department.JuridicalPerson.Name.ToLower().Contains(param.JuridicalPerson.ToLower())); // Вхождение строки
                    //.Where(o => o.User.CostsCenter.Department.JuridicalPerson.Name.Substring(0, param.JuridicalPerson.Length).ToLower() == param.JuridicalPerson.ToLower()); // Начинается со строки

                    if (param.OrderCreatedDate.HasValue)
                        orders = orders
                            .Where(o =>
                                o.CreatedDate.Year == param.OrderCreatedDate.Value.Year &&
                                o.CreatedDate.Month == param.OrderCreatedDate.Value.Month &&
                                o.CreatedDate.Day == param.OrderCreatedDate.Value.Day);

                    if (param.OrderSumm.HasValue)
                        orders = orders
                            .Where(o => o.ItogoSumm == param.OrderSumm.Value);

                    if (!string.IsNullOrEmpty(param.OrderStatus))
                        orders = orders
                            .Where(o => o.State.Name.ToLower().Contains(param.OrderStatus.ToLower())); // Вхождение строки
                    //.Where(o => o.State.Name.Substring(0, param.OrderStatus.Length).ToLower() == param.OrderStatus.ToLower()); // Начинается со строки

                    if (!string.IsNullOrEmpty(param.AccountNumber))
                        orders = orders
                            .Where(o => o.AccNumber == param.AccountNumber);

                    if (param.AccountDate.HasValue)
                        orders = orders
                            .Where(o =>
                                o.AccCreatedDate.HasValue &&
                                o.AccCreatedDate.Value.Year == param.AccountDate.Value.Year &&
                                o.AccCreatedDate.Value.Month == param.AccountDate.Value.Month &&
                                o.AccCreatedDate.Value.Day == param.AccountDate.Value.Day);

                    if (param.ExistsNotPrice.HasValue)
                        ;// Не получилось с ходу выборку сделать

                    if (!string.IsNullOrEmpty(param.StatusOtgruzki))
                        ;// Не получилось с ходу выборку сделать
                }
                #endregion Применение фильтров

                #region Применение сортировки

                if (string.IsNullOrEmpty(sortExpression))
                    sortExpression = "Id";

                bool isAscending = false;
                if (!string.IsNullOrEmpty(direction) && direction.ToLower() == "asc")
                    isAscending = true;

                var list = orders;
                if (sortExpression == "Id")
                {
                    if (isAscending)
                        list = orders.OrderBy(o => o.Id);
                    else
                        list = orders.OrderByDescending(o => o.Id);
                }
                else if (sortExpression == "CreatedUserName")
                {
                    if (isAscending)
                        list = orders.OrderBy(o => o.User.FIO);
                    else
                        list = orders.OrderByDescending(o => o.User.FIO);
                }
                else if (sortExpression == "Number")
                {
                    if (isAscending)
                        list = orders.OrderBy(o => o.Number);
                    else
                        list = orders.OrderByDescending(o => o.Number);
                }
                else if (sortExpression == "CreatedDepartmentName")
                {
                    if (isAscending)
                        list = orders.OrderBy(o => o.User.CostsCenter.Department.Name);
                    else
                        list = orders.OrderByDescending(o => o.User.CostsCenter.Department.Name);
                }
                else if (sortExpression == "CreatedCostCenterName")
                {
                    if (isAscending)
                        list = orders.OrderBy(o => o.User.CostsCenter.Name);
                    else
                        list = orders.OrderByDescending(o => o.User.CostsCenter.Name);
                }
                else if (sortExpression == "CreatedJuridicalPersonName")
                {
                    if (isAscending)
                        list = orders.OrderBy(o => o.User.CostsCenter.Department.JuridicalPerson.Name);
                    else
                        list = orders.OrderByDescending(o => o.User.CostsCenter.Department.JuridicalPerson.Name);
                }
                else if (sortExpression == "CreatedDate")
                {
                    if (isAscending)
                        list = orders.OrderBy(o => o.CreatedDate);
                    else
                        list = orders.OrderByDescending(o => o.CreatedDate);
                }
                else if (sortExpression == "ItogoSumm")
                {
                    if (isAscending)
                        list = orders.OrderBy(o => o.ItogoSumm);
                    else
                        list = orders.OrderByDescending(o => o.ItogoSumm);
                }
                else if (sortExpression == "StateName")
                {
                    if (isAscending)
                        list = orders.OrderBy(o => o.State.Name);
                    else
                        list = orders.OrderByDescending(o => o.State.Name);
                }
                else if (sortExpression == "AccountNumber")
                {
                    if (isAscending)
                        list = orders.OrderBy(o => o.AccNumber);
                    else
                        list = orders.OrderByDescending(o => o.AccNumber);
                }
                else if (sortExpression == "AccountCreatedDate")
                {
                    if (isAscending)
                        list = orders.OrderBy(o => o.AccCreatedDate);
                    else
                        list = orders.OrderByDescending(o => o.AccCreatedDate);
                }
                else if (sortExpression == "ExistsIsUnavailable")
                {
                    if (isAscending)
                        list = orders.OrderBy(o => o.OrderSpec.Where(s => s.Product.IsUnavailable == true).Any());
                    else
                        list = orders.OrderByDescending(o => o.OrderSpec.Where(s => s.Product.IsUnavailable == true).Any());
                }
                else if (sortExpression == "AccountStateName")
                {
                    if (isAscending)
                        list = orders.OrderBy(o => o.State.Name);
                    else
                        list = orders.OrderByDescending(o => o.State.Name);
                }

                #endregion Применение сортировки

                //List<Order> orderList = orders.OrderByField(sortExpression, isAscending).Skip(onPage * (numPage - 1)).Take(onPage).ToList();
                IQueryable<Order> orderList = list.Skip(onPage * (numPage - 1)).Take(onPage);

                return orderList;
        }


        /// <summary>
        /// Возвращает общее количество Заказов
        /// </summary>
        /// <returns></returns>
        public int GetOrderListCount(int currentUserId, bool onlyIts, SearchParameters parameters = null)
        {
            using (var dbcontext = CreateDataContext())
            {
                IQueryable<Order> list = GetOrderListQueryable(dbcontext, currentUserId, onlyIts, 1, 100000000, parameters);
                return list.Count();
            }
        }


        /// <summary>
        /// Сохраняет Заказ в базе данных
        /// </summary>
        /// <returns></returns>
        public int SaveOrder(int currentUserId, OrderEntity newOrder)
        {
            //new Common.Logger().LogMessage("До сохранения в БД Description='" + newOrder.Header.Description + "'");
            using (var dbcontext = CreateDataContext())
            {
                int orderId = 0;

                foreach (var spec in newOrder.Specification)
                {
                    var product = dbcontext.Product.Where(p => p.ProductId == spec.Specification.ProductId).FirstOrDefault();
                    if (product != null)
                    {
                        spec.Specification.Artikul = product.Artikul;
                        spec.Specification.ProductName = product.ProductName;
                        spec.Specification.Price = (product.Price.HasValue) ? Math.Round(product.Price.Value, 2) : (double?)null;
                        spec.Specification.IsUnavailable = product.IsUnavailable;
                        spec.Specification.SupplierName = product.SupplierName;
                        spec.Specification.SupplierArtikul = product.SupplierArtikul;
                    }
                } 
                
                Order savedOrder = EntityHelper.GetOrder(newOrder);

                if (savedOrder.Id > 0) // Если происходит обновление уже существующей записи о Заказе в БД
                {
                    savedOrder = dbcontext.Order.Where(o => o.Id == newOrder.Header.Id).FirstOrDefault();
                    if (savedOrder != null)
                    {
                        savedOrder.ContactEmail = newOrder.Header.ContactEmail;
                        savedOrder.ContactName = newOrder.Header.ContactName;
                        savedOrder.ContactPhone = newOrder.Header.ContactPhone;
                        savedOrder.Description = newOrder.Header.Description;
                        savedOrder.ItogoSumm = Math.Round(newOrder.Header.ItogoSumm, 2);
                        savedOrder.ModifiedDate = DateTime.Now;
                        savedOrder.ModifiedUserId = currentUserId;
                        savedOrder.Number = newOrder.Header.Number;
                        savedOrder.StateId = newOrder.Header.StateId;
                        savedOrder.IsModifiedByAdmin = newOrder.Header.IsModifiedByAdmin;

                        // Удаляется предварительно спецификация Заказа
                        var specs = dbcontext.OrderSpec.Where(s => s.OrderId == newOrder.Header.Id).ToList();
                        if (specs != null)
                            foreach (var spec in specs)
                                dbcontext.OrderSpec.DeleteObject(spec);

                        int rowid = 1;
                        foreach (var spec in newOrder.Specification.Select(s => s.Specification))
                        {
                            var product = dbcontext.Product.Where(p => p.ProductId == spec.ProductId).FirstOrDefault();
                            if (product != null)
                            {
                                OrderSpec ospec = new OrderSpec()
                                {
                                    Count = spec.Count,
                                    ProductId = spec.ProductId,
                                    Artikul = product.Artikul,
                                    ProductName = product.ProductName,
                                    Price = (product.Price.HasValue) ? Math.Round(product.Price.Value, 2) : (double?)null,
                                    IsUnavailable = product.IsUnavailable,
                                    SupplierName = product.SupplierName,
                                    SupplierArtikul = product.SupplierArtikul,
                                    RowId = rowid,
                                    Summa = Math.Round(spec.Summa, 2)
                                };
                                savedOrder.OrderSpec.Add(ospec);
                                rowid++;
                            }
                        }
                    }
                    else //Заказ создается
                    {
                        // Создается номер для нового документа
                        int nextNumber = 1;
                        var docNumber = dbcontext.DocNumbers.Where(n => n.DocType == "Order").FirstOrDefault();
                        if (docNumber != null)
                        {
                            nextNumber = docNumber.NextNumber;
                            docNumber.NextNumber += 1;
                        }
                        savedOrder.Number = DocNumberHelper.GetNewOrderNumber(nextNumber);

                        dbcontext.AddToOrder(savedOrder);
                    }


                    #region // Вариант сохранения через Attach
                    //dbcontext.Order.Attach(savedOrder);
                    //dbcontext.ObjectStateManager.ChangeObjectState(savedOrder, EntityState.Modified);


                    //foreach (var os in savedOrder.OrderSpec)
                    //{
                    //    if (newOrder.Specification.Select(s => s.Specification.ProductId).Contains(os.ProductId))
                    //        dbcontext.ObjectStateManager.ChangeObjectState(os, EntityState.Added);
                    //    else
                    //        dbcontext.ObjectStateManager.ChangeObjectState(os, EntityState.Deleted);
                    //}


                    //// Удаляется предварительно спецификация Заказа
                    //var specs = dbcontext.OrderSpec.Where(s => s.OrderId == newOrder.Header.Id).ToList();
                    //if (specs != null)
                    //    foreach (var spec in specs)
                    //        //dbcontext.ObjectStateManager.ChangeObjectState(spec, EntityState.Deleted);
                    //        dbcontext.OrderSpec.DeleteObject(spec);
                    #endregion // Вариант сохранения через Attach
                }
                else // Если Заказ создается
                {
                    // Создается номер для нового документа
                    int nextNumber = 1;
                    var docNumber = dbcontext.DocNumbers.Where(n => n.DocType == "Order").FirstOrDefault();
                    if (docNumber != null)
                    {
                        nextNumber = docNumber.NextNumber;
                        docNumber.NextNumber += 1;
                    }
                    savedOrder.Number = DocNumberHelper.GetNewOrderNumber(nextNumber);

                    dbcontext.AddToOrder(savedOrder);
                }

                dbcontext.SaveChanges();

                orderId = savedOrder.Id;
                return orderId;
            }
        }


        /// <summary>
        /// Удаление Закака из базы данных
        /// </summary>
        /// <param name="orderId"></param>
        public void DeleteOrder(int currentUserId, int orderId)
        {
            using (var dbcontext = CreateDataContext())
            {
                if (orderId == 0)
                    return;

                var order = dbcontext.Order.Include("OrderSpec").Where(o => o.Id == orderId).FirstOrDefault();

                if (order != null)
                {
                    // Проверка наличия исполненных Расходных накладных
                    var billsExec = dbcontext.ExpendBill.Where(b => b.OrderId == order.Id && b.StateId == (int)StateEnum.ExpendBillExecuted).ToList();
                    if (billsExec != null && billsExec.Count > 0) // Есть исполненные Расходные накладные. Удалять Заказ нельзя
                        throw new Exception("У удаляемого заказа существуют исполненные Расходные накладные. Удаление запрещено!");

                    //Удаление связных расходных накладных в статусе Сохранена
                    var bills = dbcontext.ExpendBill.Include("ExpendBillSpec").Where(b => b.OrderId == order.Id).ToList();
                    if (bills != null)
                        foreach(var b in bills)
                            dbcontext.ExpendBill.DeleteObject(b);

                    dbcontext.Order.DeleteObject(order);
                    dbcontext.SaveChanges();
                }
            }
        }


    }
}
